Slovenčina

Preskúmajte diskriminované únie v TypeScript, výkonný nástroj na vytváranie robustných a typovo bezpečných stavových automatov.

TypeScript Discriminated Unions: Budovanie typovo bezpečných stavových automatov

V oblasti vývoja softvéru je efektívne riadenie stavu aplikácie kľúčové. Stavové automaty poskytujú výkonnú abstrakciu pre modelovanie komplexných stavových systémov, čím zabezpečujú predvídateľné správanie a zjednodušujú uvažovanie o logike systému. TypeScript so svojím robustným systémom typov ponúka fantastický mechanizmus na vytváranie typovo bezpečných stavových automatov pomocou diskriminovaných únií (známych aj ako označené únie alebo algebrické dátové typy).

Čo sú diskriminované únie?

Diskriminovaná únia je typ, ktorý reprezentuje hodnotu, ktorá môže byť jednou z viacerých rôznych typov. Každý z týchto typov, známy ako člen únie, zdieľa spoločnú, odlišnú vlastnosť nazývanú diskriminant alebo tag. Tento diskriminant umožňuje TypeScript presne určiť, ktorý člen únie je aktuálne aktívny, čo umožňuje výkonné typové kontroly a automatické dopĺňanie.

Predstavte si to ako semafor. Môže byť v jednom z troch stavov: Červená, Žltá alebo Zelená. Vlastnosť 'farba' funguje ako diskriminant, ktorý nám hovorí, v akom stave sa svetlo presne nachádza.

Prečo používať diskriminované únie pre stavové automaty?

Diskriminované únie prinášajú niekoľko kľúčových výhod pri vytváraní stavových automatov v TypeScript:

Definovanie stavového automatu s diskriminovanými úniemi

Ukážme si, ako definovať stavový automat pomocou diskriminovaných únií na praktickom príklade: systém spracovania objednávok. Objednávka môže byť v nasledujúcich stavoch: Čakajúca, Spracováva sa, Odoslaná a Doručená.

Krok 1: Definujte typy stavov

Najprv definujeme jednotlivé typy pre každý stav. Každý typ bude mať vlastnosť `type` pôsobiacu ako diskriminant, spolu s akýmikoľvek údajmi špecifickými pre daný stav.


interface Pending {
  type: "pending";
  orderId: string;
  customerName: string;
  items: string[];
}

interface Processing {
  type: "processing";
  orderId: string;
  assignedAgent: string;
}

interface Shipped {
  type: "shipped";
  orderId: string;
  trackingNumber: string;
}

interface Delivered {
  type: "delivered";
  orderId: string;
  deliveryDate: Date;
}

Krok 2: Vytvorte typ diskriminovanej únie

Ďalej vytvoríme diskriminovanú úniu kombináciou týchto jednotlivých typov pomocou operátora `|` (únie).


type OrderState = Pending | Processing | Shipped | Delivered;

Teraz, `OrderState` reprezentuje hodnotu, ktorá môže byť buď `Pending`, `Processing`, `Shipped` alebo `Delivered`. Vlastnosť `type` v každom stave funguje ako diskriminant, čo umožňuje TypeScriptu rozlišovať medzi nimi.

Spracovanie prechodov medzi stavmi

Teraz, keď sme definovali náš stavový automat, potrebujeme mechanizmus na prechod medzi stavmi. Poďme vytvoriť funkciu `processOrder`, ktorá prijíma aktuálny stav a akciu ako vstup a vracia nový stav.


interface Action {
  type: string;
  payload?: any;
}

function processOrder(state: OrderState, action: Action): OrderState {
  switch (state.type) {
    case "pending":
      if (action.type === "startProcessing") {
        return {
          type: "processing",
          orderId: state.orderId,
          assignedAgent: action.payload.agentId,
        };
      }
      return state; // No state change

    case "processing":
      if (action.type === "shipOrder") {
        return {
          type: "shipped",
          orderId: state.orderId,
          trackingNumber: action.payload.trackingNumber,
        };
      }
      return state; // No state change

    case "shipped":
      if (action.type === "deliverOrder") {
        return {
          type: "delivered",
          orderId: state.orderId,
          deliveryDate: new Date(),
        };
      }
      return state; // No state change

    case "delivered":
      // Order is already delivered, no further actions
      return state;

    default:
      // This should never happen due to exhaustiveness checking
      return state; // Or throw an error
  }
}

Vysvetlenie

Využitie kontroly vyčerpania

Kontrola vyčerpania TypeScript je výkonná funkcia, ktorá zaisťuje, že spracúvate všetky možné stavy vo vašom stavovom automate. Ak pridáte nový stav do únie `OrderState`, ale zabudnete aktualizovať funkciu `processOrder`, TypeScript označí chybu.

Ak chcete povoliť kontrolu vyčerpania, môžete použiť typ `never`. Vnútri prípadu `default` vášho príkazu switch priraďte stav premennej typu `never`.


function processOrder(state: OrderState, action: Action): OrderState {
  switch (state.type) {
    // ... (previous cases) ...

    default:
      const _exhaustiveCheck: never = state;
      return _exhaustiveCheck; // Or throw an error
  }
}

Ak príkaz `switch` spracováva všetky možné hodnoty `OrderState`, premenná `_exhaustiveCheck` bude typu `never` a kód sa skompiluje. Ak však do únie `OrderState` pridáte nový stav a zabudnete ho spracovať v príkaze `switch`, premenná `_exhaustiveCheck` bude iného typu a TypeScript vyvolá chybu v čase kompilácie, ktorá vás upozorní na chýbajúci prípad.

Praktické príklady a aplikácie

Diskriminované únie sú použiteľné v širokej škále scenárov okrem jednoduchých systémov spracovania objednávok:

Príklad: Riadenie stavu používateľského rozhrania

Pouvažujme o jednoduchom príklade riadenia stavu komponentu používateľského rozhrania, ktorý získava dáta z API. Môžeme definovať nasledujúce stavy:


interface Initial {
  type: "initial";
}

interface Loading {
  type: "loading";
}

interface Success {
  type: "success";
  data: T;
}

interface Error {
  type: "error";
  message: string;
}

type UIState = Initial | Loading | Success | Error;

function renderUI(state: UIState): React.ReactNode {
  switch (state.type) {
    case "initial":
      return 

Kliknite na tlačidlo na načítanie údajov.

; case "loading": return

Načítava sa...

; case "success": return
{JSON.stringify(state.data, null, 2)}
; case "error": return

Chyba: {state.message}

; default: const _exhaustiveCheck: never = state; return _exhaustiveCheck; } }

Tento príklad ukazuje, ako možno diskriminované únie použiť na efektívne riadenie rôznych stavov komponentu používateľského rozhrania, čím sa zabezpečí, že používateľské rozhranie sa zobrazí správne na základe aktuálneho stavu. Funkcia `renderUI` spracováva každý stav primerane a poskytuje jasný a typovo bezpečný spôsob riadenia používateľského rozhrania.

Osvedčené postupy pri používaní diskriminovaných únií

Ak chcete efektívne využívať diskriminované únie vo svojich projektoch TypeScript, zvážte nasledujúce osvedčené postupy:

Pokročilé techniky

Podmienené typy

Podmienené typy je možné kombinovať s diskriminovanými úniemi a vytvárať ešte výkonnejšie a flexibilnejšie stavové automaty. Napríklad môžete použiť podmienené typy na definovanie rôznych návratových typov pre funkciu na základe aktuálneho stavu.


function getData(state: UIState): T | undefined {
  if (state.type === "success") {
    return state.data;
  }
  return undefined;
}

Táto funkcia používa jednoduchý príkaz `if`, ale môže byť rozsiahlejšia pomocou podmienených typov, aby sa zaistilo, že sa vždy vráti konkrétny typ.

Typy utilít

Typy utilít TypeScriptu, ako napríklad `Extract` a `Omit`, môžu byť užitočné pri práci s diskriminovanými úniemi. `Extract` umožňuje extrahovať konkrétnych členov z typu únie na základe podmienky, zatiaľ čo `Omit` umožňuje odstrániť vlastnosti z typu.


// Extrahujte stav "success" z únie UIState
type SuccessState = Extract, { type: "success" }>;

// Vynechajte vlastnosť 'message' z rozhrania Error
type ErrorWithoutMessage = Omit;

Príklady z reálneho sveta naprieč rôznymi odvetviami

Sila diskriminovaných únií sa rozširuje naprieč rôznymi odvetviami a aplikačnými oblasťami:

Záver

Diskriminované únie TypeScript poskytujú výkonný a typovo bezpečný spôsob, ako budovať stavové automaty. Jasným definovaním možných stavov a prechodov môžete vytvoriť robustnejší, udržiavateľnejší a zrozumiteľnejší kód. Kombinácia typovej bezpečnosti, kontroly vyčerpania a vylepšeného dopĺňania kódu robí z diskriminovaných únií neoceniteľný nástroj pre každého vývojára TypeScript, ktorý sa zaoberá komplexným riadením stavu. Prijmite diskriminované únie vo svojom ďalšom projekte a zažite výhody typovo bezpečného riadenia stavu na vlastnej koži. Ako sme ukázali na rôznych príkladoch od elektronického obchodu po zdravotníctvo a logistiku až po vzdelávanie, princíp typovo bezpečného riadenia stavu prostredníctvom diskriminovaných únií je univerzálne použiteľný.

Či už vytvárate jednoduchý komponent používateľského rozhrania alebo komplexnú podnikovú aplikáciu, diskriminované únie vám môžu pomôcť efektívnejšie riadiť stav a znížiť riziko chýb za behu. Takže sa do toho pustite a preskúmajte svet typovo bezpečných stavových automatov s TypeScript!